import LAYER_CONFIG from "./config"
import { mountToWindow } from "../../components/de-work/map"

class LayerManager {
  constructor (id, options) {
    const { viewer } = options
    this._options = options
    this._viewer = viewer
    this._id = `${id}LayerManager`
    this._viewerId = id
    this._layers = {}
    this._groups = {}
    this._show = false
    this._layerCfg = LAYER_CONFIG[this._viewerId]
    this._events = {}
  }

  get bindViewerId () {
    return this._viewerId
  }

  get layerCfg () {
    return this._layerCfg
  }

  set show (s) {
    this._show = s
    this.eachLayer((layer) => {
      layer.show = s
    })
  }

  get show () {
    return this._show
  }

  get id () {
    return this._id
  }

  get viewer () {
    return this._viewer
  }

  get layers () {
    return this._layers
  }

  eachLayer (method, context) {
    Object.keys(this._layers).forEach((key) => {
      method && method.call(context || this, this._layers[key])
    })
    return this
  }

  getLayersByGroupId (groupId) {
    let res = []
    console.log(this._groups)
    if (this._groups[groupId]) {
      res = Object.keys(this._groups[groupId]).map(k => this._groups[groupId][k])
    }
    return res
  }

  getLayers () {
    return Object.keys(this._layers).map(k => this._layers[k])
  }

  /**
   * get layers By layerType
   * @param {DE.LayerType} type
   * @return {Array} layers
   */
  getLayersByType (type) {
    return this._viewer?._layerCache[type]
  }

  showLayersByType (type, flag) {
    const layers = this._viewer?._layerCache[type]
    layers && layers.forEach(layer => {
      layer.show = flag
    })
  }

  showLayersByGroupId (groupId, flag) {
    const layers = this.getLayersByGroupId(groupId)
    layers && layers.forEach(layer => {
      layer.show = flag
    })
  }

  registerLayers () {
    if (!this._viewer) {
      return
    }
    if (this._layerCfg) {
      if (this._layerCfg && Array.isArray(this._layerCfg)) {
        this._layerCfg.forEach(layerCfg => {
          this.registerLayer(layerCfg)
        })
      }
    }
  }

  /**
   * @typedef LayerCfg
   * @type {Object}
   * @property {string} id 图层di
   * @property {string} name 图层name
   * @property {string} type 图层类型
   * @property {boolean} mountToWindow 图层是否可以挂载到window对象中
   * @property {string} groupId 图层组id
   * @property {Function} contextMenu 图层的右键菜单
   * @property {Array} events 图层的事件列表
   */

  /**
   * 注册图层
   * @param {LayerCfg} layerCfg
   */
  registerLayer (layerCfg) {
    let layer
    const layerId = layerCfg.id
    !this._events[layerId] && (this._events[layerId] = {})

    if (layerId && !this._layers[layerId]) {
      layer = this.generateLayer(layerId, {
        ...layerCfg,
        viewer: this._viewer
      })

      layer.name = layerId

      if (layerCfg.groupId) {
        const groupId = layerCfg.groupId
        !this._groups[groupId] && (this._groups[groupId] = {})
        this._groups[groupId][layerId] = layer
        layer.groupId = layerCfg.groupId
      }
      this._layers[layerId] = layer
      // 将图层挂载到window对象上
      layerCfg.mountToWindow && mountToWindow({ [`${layerId}`]: layer })
      this._viewer.addLayer(layer)

      // 绑定图层右键菜单和事件
      const {
        contextMenu,
        events
      } = layerCfg
      contextMenu && layer.bindContextMenu(contextMenu(layer, this._options))
      events && events.length && events.forEach(event => {
        this._events[layerId][event.type] = event.callback(layer, this._options)
        layer.on(DE.LayerEventType[event.type], this._events[layerId][event.type], this._options.context || this)
      })
    } else {
      layer = this._layers[layerId]
    }

    return layer
  }

  /**
   * 清空图层的所有overlays
   */
  clearOverlays () {
    Object.keys(this._layers).forEach(k => {
      const layer = this._layers[k]
      layer && layer.clear()
    })
  }

  /**
   * 删除viewer绑定的所有图层
   */
  removeAllLayers () {
    Object.keys(this._layers).forEach(k => {
      this.removeLayerById(k)
    })
  }

  cancelEditing () {
    this.eachLayer((layer) => {
      layer && layer.stopEditing && layer.stopEditing()
    })
  }

  /**
   * 基于layerId获得layer本体
   */
  getLayerById (layerId) {
    if (this._layers[layerId]) {
      return this._layers[layerId]
    } else {
      return undefined
    }
  }

  deleteProperty (obj, property) {
    if (obj && typeof obj[property] !== "undefined") {
      obj[property] = undefined
      delete obj[property]
    }
  }

  removeLayerByGroupId (groupId) {
    const layers = this.getLayersByGroupId(groupId)
    layers.forEach(layer => {
      this.removeLayerById(layer.layerId)
    })
  }

  /**
   * 基于图层id删除图层
   * @param layerId
   */
  removeLayerById (layerId) {
    const layer = this._layers[layerId]
    if (layerId && layer) {
      // 取消event
      const layerCfg = this.layerCfg.find(cfg => cfg.id === layerId)
      layerCfg?.events?.length && layerCfg.events.forEach(event => {
        layer.off(DE.LayerEventType[event.type], this._events[layerId][event.type], this._options.context || this)
        this.deleteProperty(this._events[layerId], event.type)
      })
      this.deleteProperty(this._events, layerId)
      this._layerCfg = this.layerCfg.filter(cfg => cfg.id !== layerId)

      // 取消group注册
      const groupId = this._layers[layerId].groupId
      if (groupId && this._groups[groupId] && this._groups[groupId][layerId]) {
        this.deleteProperty(this._groups[groupId], layerId)
        if (!Object.keys(this._groups[groupId])) {
          this.deleteProperty(this._groups, groupId)
        }
      }
      // 删除图层
      this._viewer && this._viewer.removeLayer(this._layers[layerId])
      this.deleteProperty(this._layers, layerId)
      if (window[`$${layerId}`]) {
        this.deleteProperty(window, `$${layerId}`)
      }
    }
  }

  /**
   * get Layer
   * @param id
   * @param options
   * @return {DE.VectorLayer | DE.PrimitiveLayer | DE.TilesetLayer | DE.HtmlLayer | DE.DynamicLayer | DE.ClusterLayer | DE.CzmlLayer | DE.GeoJsonLayer | DE.KmlLayer}
   */
  generateLayer (id, options) {
    let layer
    const {
      viewer,
      type = DE.LayerType.VECTOR,
      url = ""
    } = options
    options.viewer && delete options.viewer
    options.type && delete options.type
    options.url && delete options.url
    switch (DE.LayerType[type]) {
      case DE.LayerType.VECTOR:
        layer = new DE.VectorLayer(id, { clickClose: true })
        break
      case DE.LayerType.PRIMITIVE:
        layer = new DE.PrimitiveLayer(id)
        break
      case DE.LayerType.TILESET:
        layer = new DE.TilesetLayer(id)
        break
      case DE.LayerType.HTML:
        layer = new DE.HtmlLayer(id)
        break
      case DE.LayerType.Dynamic:
        layer = new DE.DynamicLayer(id)
        break
      case DE.LayerType.CLUSTER:
        layer = new DE.ClusterLayer(id)
        break
      case DE.LayerType.CZML:
        layer = new DE.CzmlLayer(id, url, options)
        break
      case DE.LayerType.GEOJSON:
        layer = new DE.GeoJsonLayer(id, url, options)
        break
      case DE.LayerType.KML:
        layer = new DE.KmlLayer(id, url, options)
        break
    }
    return layer
  }
}


export function registerLayers (id, options) {
  const layerManagerId = `${id}LayerManager`
  let layerManager = window[layerManagerId]
  if (!layerManager) {
    layerManager = new LayerManager(id, {
      ...options
    })
    mountToWindow({ [layerManagerId]: layerManager })
  }
  layerManager.registerLayers()
  console.log(layerManager.getLayers())
  return layerManager
}
